package finalVersion;

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.*;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JList;
import javax.swing.border.TitledBorder;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.FlowLayout;
import java.awt.Font;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import java.awt.Insets;

import javax.swing.DefaultListModel;
import javax.swing.JMenuBar;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenuItem;
import javax.swing.JMenu;
import javax.swing.ListModel;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.event.WindowStateListener;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import javax.swing.JSeparator;
import net.miginfocom.swing.MigLayout;
import javax.swing.JLayeredPane;
import javax.swing.AbstractListModel;
import javax.swing.ListSelectionModel;
import javax.swing.border.EtchedBorder;
import javax.swing.event.ListDataListener;

import java.awt.Color;
import java.io.*;
import java.net.*;
import java.util.*;
import java.applet.*;
import java.util.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class ClientGUI extends JFrame implements ActionListener {
	// code generated by Swing designer
	private JPanel contentPane;
	private JTextField chatTextField;
	private JTextArea chatArea;
	private JList list;
	private JButton btnSend;
	private JMenu mnAction;
	private JMenu mnAbout;
	private JMenuItem aboutDialog;
	private JMenuItem mntmExit;
	private JScrollPane ListScroll;
	private JDialog aboutD;

	// Communicate with sever
	private Socket clientSocket;
	private String userID = null;
	private Thread read;
	private String toSerVer = null;// String send to server with format
									// "Protocol:..."
	private String fromSerVer = null;// String receive from server with format
										// "Protocol:..."
	private PrintWriter serverOut = null;// oupustream to server
	private BufferedReader ServerIn = null;// inputstream from server
	private List<String> userList = new ArrayList<String>();// a list contain
															// user online

	// Run as a server
	private ServerSocket welcomSoc = null;
	private JButton btnChatPrivate;
	private int listenPort;
	private List<ChatGUI> directGUI;

	/**
	 * Launch the application.
	 */
	/**
	 * Create the frame.
	 */
	public ClientGUI() {

		setTitle("Client");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 679, 524);

		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);

		mnAction = new JMenu("Action");
		menuBar.add(mnAction);

		mntmExit = new JMenuItem("Exit");
		mnAction.add(mntmExit);
		// send "Disconnect:" to server to inform server to close this
		// connection
		mntmExit.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				serverOut.println("Disconnect:");
				serverOut.flush();
				

			}
		});

		mnAbout = new JMenu("About");
		menuBar.add(mnAbout);

		aboutDialog = new JMenuItem("About Client");
		aboutDialog.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (aboutD == null) {
					aboutD = new AboutDialog("About chat client");
				}
				aboutD.setVisible(true);
			}
		});
		
		
		
		
		mnAbout.add(aboutDialog);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(new BorderLayout(0, 0));

		JPanel panel_1 = new JPanel();
		contentPane.add(panel_1, BorderLayout.SOUTH);
		panel_1.setLayout(new MigLayout("", "[][grow]", "[][]"));

		JSeparator separator_1 = new JSeparator();
		panel_1.add(separator_1, "cell 0 0 2 1,growx");

		JLabel lblChat = new JLabel("Chat");
		panel_1.add(lblChat, "cell 0 1,alignx trailing");

		chatTextField = new JTextField();
		chatTextField.addActionListener(this);

		panel_1.add(chatTextField, "flowx,cell 1 1,growx");
		chatTextField.setColumns(10);

		btnSend = new JButton("Send");
		panel_1.add(btnSend, "cell 1 1");
		btnSend.addActionListener(this);

		ListScroll = new JScrollPane();
		ListScroll.setViewportBorder(new TitledBorder(new EtchedBorder(
				EtchedBorder.LOWERED, null, null), "User Online",
				TitledBorder.LEADING, TitledBorder.TOP, null,
				new Color(0, 0, 0)));
		contentPane.add(ListScroll, BorderLayout.EAST);

		list = new JList();
		list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		list.setFixedCellWidth(200);
		list.setEnabled(true);

		ListScroll.setViewportView(list);

		btnChatPrivate = new JButton("Chat Private");
		btnChatPrivate.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent arg0) {

				String chatDirect = "ChatWith:"
						+ ((String) list.getSelectedValue());
				System.out.println(chatDirect);
				serverOut.println(chatDirect);
				serverOut.flush();

			}
		});
		ListScroll.setColumnHeaderView(btnChatPrivate);

		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setViewportBorder(new TitledBorder(new EtchedBorder(
				EtchedBorder.LOWERED, null, null), "Chat room",
				TitledBorder.LEADING, TitledBorder.TOP, null,
				new Color(0, 0, 0)));
		contentPane.add(scrollPane, BorderLayout.CENTER);

		chatArea = new JTextArea();
		chatArea.setEditable(false);
		scrollPane.setViewportView(chatArea);

		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosed(WindowEvent arg0) {
				serverOut.println("Disconnect:");
				serverOut.flush();
			}
		});

	}

	// Receive socket with parameter taken from connectingGUI
	public void setSocket(Socket clientSocket) {
		this.clientSocket = clientSocket;
	}

	public void setUserID(String user) {
		this.userID = user;
	}

	public void setPort(String port) {
		this.listenPort = Integer.parseInt(port);
	}
	
	private void exit() {
		try {
			clientSocket.close();
		} catch (Exception e) {
			System.err
					.println("Error while shutting down the server connection.");
		}
		System.exit(0);
		this.dispose();
	}

	public void doconnect() {
		try {
			// init GUI and register with Server
			
			this.setTitle("Client::" + userID);
			serverOut = new PrintWriter(clientSocket.getOutputStream());
			ServerIn = new BufferedReader(new InputStreamReader(clientSocket
					.getInputStream()));
			toSerVer = "Connect:" + userID + ":" + listenPort + ":"
					+ clientSocket.getLocalAddress().getHostAddress();
			serverOut.println(toSerVer);
			serverOut.flush();
			RemoteReader r = new RemoteReader();
			read = new Thread(r);
			read.start();

			// run as a server
			directGUI = new ArrayList<ChatGUI>();
			welcomSoc = new ServerSocket(listenPort);
			Thread runAsServer = new Thread(new ReceiveRequest());
			runAsServer.start();

		} catch (Exception ex) {
			System.out.println(ex);
		}
	}

	public void refreshlist() {
		String display = "";
		for (String s : userList) {
			if (display.equals("")) {
				display = s;
			} else {
				display = display + ":" + s;
			}
		}
		String[] spl = display.split(":");
		list.setListData(spl);
	}

	// Thread run permanently to procress request from other clients
	private class ReceiveRequest implements Runnable {
		public void run() {
			try {
				while (true) {
					Socket receiveRequest = welcomSoc.accept();
					handleRequest(receiveRequest);

				}
			} catch (Exception e) {
				System.out.println(e);
			}
		}
	}

	private void handleRequest(Socket s) {
		ChatGUI c = new ChatGUI();
		c.setSocket(s);
		c.setID(userID);
		c.run();
		
	}

	// Thread run permanently to receive data from server
	private class RemoteReader implements Runnable {
		public void run() {
			try {
				while (true) {
					fromSerVer = ServerIn.readLine();
					if (fromSerVer != null) {
						if (fromSerVer.startsWith("Update")) {
							String[] spl = fromSerVer.substring(7).split(":");
							for (String s : spl) {
								if (!userList.contains(s)) {
									userList.add(s);
								}
							}
							refreshlist();

						} else if (fromSerVer.startsWith("Text")) {
							chatArea.append(fromSerVer.substring(5) + "\n");
							chatArea.setCaretPosition(chatArea.getDocument()
									.getLength() - 1);
						} else if (fromSerVer.startsWith("Disconnect:")) {
							if (userID.equals(fromSerVer.substring(11))) {
								exit();

							}
							userList.remove(fromSerVer.substring(11));
							refreshlist();

						} else if (fromSerVer.startsWith("ChatPrivate:")) {
							
							//Create a new socket to the ip address that server send back
							String[] spl = fromSerVer.substring(12).split(":");
							ChatGUI c = new ChatGUI();
							c.setDetailConnection(spl[0], Integer
									.parseInt(spl[1]));
							c.setID(userID);
							c.run();
							
						} else {

						}
					}
				}
			} catch (Exception e) {
				System.err.println("Error while reading from server.");
				e.printStackTrace();
			}
		}
	}
		    
	    private class AboutDialog extends JDialog implements ActionListener  {
	        public AboutDialog(String title) {	
	        	setTitle(title);
	            add(new JLabel(	"========"+
	            				"Code by : Lam Phuoc Thinh" + "| | |"+
	            				"Design by : Truong Thanh Sang" +
	            				"========")
	            ,BorderLayout.NORTH);
	            JButton b = new JButton("OK");
	            add(b,BorderLayout.SOUTH);
	            b.addActionListener(this);
	            pack();
	        }
	        // Hide the dialog box when the OK button is pushed
	        public void actionPerformed(ActionEvent e) {
	            setVisible(false);
	        }
	    }

	@Override
	// Action perfrom when "send" buttun war pressed
	public void actionPerformed(ActionEvent arg0) {
		String chat = chatTextField.getText();
		chatTextField.setText("");
		String sendtoServer = "Text:" + userID + ":: " + chat;
		try {
			serverOut.println(sendtoServer);
			serverOut.flush();
		} catch (Exception e) {
			System.out.println(e);
		}

	}

}
